package com.midea.thread;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @description：lock和Condition实现生产者和消费者
 * 1.性质区别
 *  synchronized属于JVM层面，属于java的关键字;
 *  Lock是具体类（java.util.concurrent.locks.Lock）是api层面的锁
 * 2. 是否需要手动释放锁
 *  synchronized：不需要用户去手动释放锁，当synchronized代码执行后，系统会自动让线程释放对锁的占用。
 *  ReentrantLock：则需要用户去手动释放锁，若没有主动释放锁，就有可能出现死锁的现象，需要lock() 和 unlock() 配置try catch语句来完成
 * 3. 是否可中断
 *  synchronized：不可中断，除非抛出异常或者正常运行完成。
 *  ReentrantLock：可中断，可以设置超时方法
 * 4.加锁是否公平
 *  synchronized：非公平锁
 *  ReentrantLock：默认非公平锁，构造函数可以传递boolean值，true为公平锁，false为非公平锁
 * 5.锁绑定多个条件Condition
 *  synchronized：没有，要么随机，要么全部唤醒
 *  ReentrantLock：用来实现分组唤醒需要唤醒的线程，可以精确唤醒，而不是像synchronized那样，要么随机，要么全部唤醒
 * @author: wangwl23
 * @create: 2022-04-08 15:55
 */
public class ProducerConsumerDemo2 {
    public static void main(String[] args) {
        Task t = new Task();
        Producer producer = new Producer(t);
        Consumer consumer = new Consumer(t);

        new Thread(producer,"生产者A").start();
        new Thread(consumer,"消费者A").start();
        new Thread(producer,"生产者B").start();
        new Thread(consumer,"消费者B").start();

    }
}

class Task {
    private int product = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void produce() {
        lock.lock();
        try {
            while (product >= 1) {
                System.out.println(Thread.currentThread().getName() + "已满");
                condition.await();
            }
            ++product;
            System.out.println(Thread.currentThread().getName() + "进货成功，剩下" + product);
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void sale() {
        lock.lock();
        try {
            while (product <= 0) {
                System.out.println(Thread.currentThread().getName() + "没有买到货");
                condition.await();
            }
            --product;
            System.out.println(Thread.currentThread().getName() + "买到了货物，剩下" + product);
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

//生产者
class Producer implements Runnable {
    private Task task;
    public Producer(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            task.produce();
        }
    }
}

//消费者
class Consumer implements Runnable {
    private Task task;
    public Consumer(Task task) {
        this.task = task;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            task.sale();
        }
    }
}
